//
//  main.m
//  testLock
//
//  Created by Open on 5/15/15.
//  Copyright (c) 2015 open-groupe. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TestObject.h"

 void useLock()
{
    TestObject *obj = [[TestObject alloc] init];
    NSLock *lock = [[NSLock alloc] init];
    
    // thread 1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        [lock lock];
        [obj method1];
        sleep(10);
        [lock unlock];
    });
    // theread 2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        [lock lock];
        [obj method2];
        [lock unlock];
        
    });
    
}
// use synchronized
void useSynchronized()
{
    TestObject *obj = [[TestObject alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized(obj){
            [obj method1];
            sleep(5);
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        @synchronized(obj){
            [obj method2];
            
        }
    });
    
}

// use pThread
void usePthread()
{
    TestObject *obj = [[TestObject alloc] init];
    
    __block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         pthread_mutex_lock(&mutex);
         [obj method1];
         sleep(5);
         pthread_mutex_unlock(&mutex);
     });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        pthread_mutex_lock(&mutex);
        [obj method2];
        
        pthread_mutex_unlock(&mutex);
    });
}

// GCD Lock
void  useGCDLock()
{
    TestObject *obj = [[TestObject alloc] init];
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [obj method1];
        sleep(10);
        dispatch_semaphore_signal(semaphore);
    });
    
    //线程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [obj method2];
        dispatch_semaphore_signal(semaphore);
    });
    
}
//use  NSRecursiveLock递归锁
void useRecursiveLock()
{
    NSLock *theLock = [[NSLock alloc] init];
    // the thread 1 will dead in runtime
    // use NSRecursiveLock will work
    TestObject *obj =[[TestObject alloc] init];
    
    // thread 1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        static void(^TestMethod)(int);
        TestMethod = ^(int value){
            [theLock lock];
            if( value > 0)
            {
                [obj method1];
                sleep(5);
                TestMethod(value -1);
            }
            [theLock unlock];
        };
        TestMethod(5);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        [theLock lock];
        [obj method2];
        [theLock unlock];
    });
    
    
    // use the nsRecursiveLock
    NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        static void (^RecursiveMethod)(int);
        
        RecursiveMethod = ^(int value) {
            
            [lock lock];
            if (value > 0) {
                
                NSLog(@"value = %d", value);
                sleep(2);
                RecursiveMethod(value - 1);
            }
            [lock unlock];
        };
        
        RecursiveMethod(5);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        sleep(2);
        BOOL flag = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        if (flag) {
            NSLog(@"lock before date");
            
            [lock unlock];
        } else {
            NSLog(@"fail to lock before date");
        }
    });
}

//NSConditionLock条件锁
void useConditionLock()
{
   NSConditionLock *theLock = [[NSConditionLock alloc] init];
   
   //线程2
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       [theLock lockWhenCondition:4];
       NSLog(@"thread2");
       [theLock unlock];
   });
    
    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i=0;i<=4;i++)
        {
            [theLock lock];
            NSLog(@"thread1:%d",i);
            sleep(1);
            [theLock unlockWithCondition:i];
        }
    });
}
                   
//NSDistributedLock分布式锁
void useDistrubutedLock()
{
    // use in different application
    // application a
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
    [lock breakLock];
    [lock tryLock];
    sleep(10);
    [lock unlock];
    NSLog(@"appA: OK");
});
    // application b
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
        
        while (![lock tryLock]) {
            NSLog(@"appB: waiting");
            sleep(1);
        }
        [lock unlock];
        NSLog(@"appB: OK");
    });
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
//        useLock();
//        useSynchronized();
//        usePthread();
        useConditionLock();
        sleep(20);
    }
    return 0;
}
